package org.itsolutions.javaBackup.core;

import java.util.NavigableSet;
import java.util.Set;
import java.util.TreeSet;

import org.itsolutions.javaBackup.core.properties.CoreProperty;
import org.itsolutions.javaBackup.exceptions.AException;
import org.itsolutions.javaBackup.logger.ELogLevel;
import org.itsolutions.javaBackup.logger.ILogger;
import org.itsolutions.javaBackup.logger.LoggerHelper;
import org.itsolutions.javaBackup.spi.IModuleStartStopTask;
import org.itsolutions.javaBackup.spi.IServiceWithLifecycle;

import com.google.inject.Inject;

/**
 * @author Tomas Fecko
 *
 */
public final class CoreController implements IServiceWithLifecycle {

	private static final ILogger 			LOGGER = LoggerHelper.getLogger(CoreController.class);	
	private final Set<IModuleStartStopTask> mModuleStartStopTasks;

	/**
	 * 
	 * @param pModuleStartTasks modules start tasks
	 */
	@Inject CoreController(Set<IModuleStartStopTask> pModuleStartTasks) {
		mModuleStartStopTasks = pModuleStartTasks;
	}

	@Override
	public void startService() throws AException {
		LOGGER.log(ELogLevel.DEBUG, "Starting modules in order:");
		NavigableSet<SortedWrapper> sortedSet = sortSet(mModuleStartStopTasks);
		if (LOGGER.isEnabledFor(ELogLevel.INFO)) {
			int counter = 0;
			for (SortedWrapper wrapper : sortedSet) {
				LOGGER.log(ELogLevel.INFO, "Order: ", ++counter, " Task: ", wrapper.getStartStopTask());				
			}
		}
		for (SortedWrapper wrapper : sortedSet) {
			try {
				LOGGER.log(ELogLevel.DEBUG, "Calling module start task:", wrapper.getStartStopTask());
				if (!wrapper.getStartStopTask().isStarted()) {
					wrapper.getStartStopTask().start();
				}
			} catch (AException e) {
				LOGGER.log(ELogLevel.ERROR, e);
				if (CoreProperty.SHOULD_EXCEPTION_STOP_BOOTSTRAPPING.get()) {
					break;
				}
			}
		}
		LOGGER.log(ELogLevel.DEBUG, "Modules started.");	
	}

	@Override
	public void stopService() throws AException {
		LOGGER.log(ELogLevel.DEBUG, "Stopping modules...");
		NavigableSet<SortedWrapper> sortedSet = sortSet(mModuleStartStopTasks);
		for (SortedWrapper wrapper : sortedSet) {
			LOGGER.log(ELogLevel.DEBUG, "Calling module stop task:", wrapper.getStartStopTask());
			if (wrapper.getStartStopTask().isStarted()) {
				wrapper.getStartStopTask().stop();
			}
		}
		LOGGER.log(ELogLevel.DEBUG, "Modules stopped.");		
	}

	/**
	 * 
	 * @param pUnsortedSet
	 * @return
	 */
	private NavigableSet<SortedWrapper> sortSet(Set<IModuleStartStopTask> pUnsortedSet) {
		NavigableSet<SortedWrapper> returnSet = new TreeSet<SortedWrapper>();
		int counter = 0;
		for (IModuleStartStopTask task : pUnsortedSet) {
			returnSet.add(new SortedWrapper(counter++, task));
		}
		return returnSet;
	}

	/**
	 * Wrapper sorts the IModuleStartStopTask objects based on order in EModule.
	 * @author Tomas Fecko
	 */
	private static final class SortedWrapper implements Comparable<SortedWrapper> {

		private final int					mCounter;
		private final IModuleStartStopTask 	mStartStopTask;

		/**
		 * 
		 * @param pCounter
		 * @param pStartStopTask
		 */
		private SortedWrapper(int pCounter, IModuleStartStopTask pStartStopTask) {
			mCounter = pCounter;
			mStartStopTask = pStartStopTask;
		}

		@Override
		public int compareTo(SortedWrapper pWrapper) {
			if (mStartStopTask.getModule().ordinal() > pWrapper.getStartStopTask().getModule().ordinal()) {
				return 1;
			} else if (mStartStopTask.getModule().ordinal() < pWrapper.getStartStopTask().getModule().ordinal()) {
				return -1;
			} else {
				if (mCounter > pWrapper.getCounter()) {
					return 1;
				} else if (mCounter < pWrapper.getCounter()) {
					return -1;
				} else {
					LOGGER.log(ELogLevel.ERROR, "There is problem during the module start stop task sorting.");
					return 0;
				}
			}
		}

		/**
		 * @return the counter
		 */
		private int getCounter() {
			return mCounter;
		}

		/**
		 * @return the startStopTask
		 */
		private IModuleStartStopTask getStartStopTask() {
			return mStartStopTask;
		}
	}
}




